diff --git a/README.md b/README.md index 24fee8a..d1e41e7 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,7 @@ FunDSP supports `no_std` environments. To enable `no_std`, disable the feature `std`, which is enabled by default. The `alloc` crate is still needed for components that allocate memory. -In a `no_std` environment, -audio file reading and writing is not available. +Audio file reading and writing is not available in `no_std`. ```rust [dependencies] @@ -330,7 +329,7 @@ Arithmetic operators are applied to outputs channelwise. Arithmetic between two components never broadcasts channels: channel arities have to match always. -Direct arithmetic with `f32` and `f64` values, however, broadcasts to an arbitrary number of channels. +Direct arithmetic with `f32` values, however, broadcasts to an arbitrary number of channels. The negation operator broadcasts also: `-A` is equivalent with `(0.0 - A)`. @@ -944,13 +943,13 @@ a setting listener. let (sender, equalizer) = listen(equalizer); ``` -Then, we can send settings of the form (band, (center, Q, gain)). +Then, we can send settings to change center frequency, Q and gain. The settings are available because we constructed the filter using the `bell_hz` form. Set band 1 to amplify by 3 dB at 1000 Hz with Q set to 2.0: ```rust -sender.try_send((1, (1000.0, 2.0, db_amp(3.0)))).expect("Cannot send setting."); +sender.try_send(Setting::center_q_gain(1000.0, 2.0, db_amp(3.0)).index(1)).expect("Cannot send setting."); ``` ## evcxr diff --git a/src/net.rs b/src/net.rs index 464056e..a38b010 100644 --- a/src/net.rs +++ b/src/net.rs @@ -77,9 +77,9 @@ struct Vertex { pub tick_output: Vec, /// Stable, globally unique ID for this vertex. pub id: NodeId, - /// This is set if all vertex inputs are sourced from matching outputs of the indicated node. - /// We can then omit copying and use the node outputs directly. - pub source_vertex: Option, + /// This is set if all vertex inputs are sourced from successive outputs of the indicated node. + /// We can then omit copying and use the source node outputs directly. + pub source_vertex: Option<(NodeIndex, usize)>, /// Network revision in which this vertex was changed last. pub changed: u64, } @@ -117,36 +117,35 @@ impl Vertex { self.tick_output.len() } - /// Update source vertex shortcut. - pub fn update_source_vertex(&mut self) { - self.source_vertex = None; + /// Preallocate everything. + pub fn allocate(&mut self) { + self.unit.allocate(); + } + + /// Calculate source vertex and source port. + pub fn get_source_vertex(&self) -> Option<(NodeIndex, usize)> { if self.inputs() == 0 { - return; + return None; } let mut source_node = 0; + let mut source_port = 0; for i in 0..self.inputs() { - match self.source[i].source { + let source = self.source[i].source; + match source { Port::Local(node, port) => { - if port != i { - return; - } if i == 0 { source_node = node; - } else if source_node != node { - return; + source_port = port; + } else if source_node != node || source_port + i != port { + return None; } } _ => { - return; + return None; } } } - self.source_vertex = Some(source_node); - } - - /// Preallocate everything. - pub fn allocate(&mut self) { - self.unit.allocate(); + Some((source_node, source_port)) } } @@ -667,8 +666,9 @@ impl Net { /// Compute and store node order for this network. fn determine_order(&mut self) { - for vertex in self.vertex.iter_mut() { - vertex.update_source_vertex(); + // Update source vertex shortcut. + for j in 0..self.vertex.len() { + self.vertex[j].source_vertex = self.vertex[j].get_source_vertex(); } let mut order = Vec::new(); if !self.determine_order_in(&mut order) { @@ -826,6 +826,7 @@ impl Net { match self.vertex[index].source[channel].source { Port::Local(node, port) => { assert!(node < self.size()); + // Self connections are prohibited. assert!(node != index); assert!(port < self.vertex[node].outputs()); } @@ -835,6 +836,13 @@ impl Net { _ => (), } } + if let Some((source_node, source_port)) = self.vertex[index].source_vertex { + assert!(source_node < self.size()); + assert!(source_node != index); + assert!( + source_port + self.vertex[index].inputs() <= self.vertex[source_node].outputs() + ); + } } } @@ -1031,7 +1039,7 @@ impl AudioUnit for Net { let simd_size = simd_items(size); // Iterate units in network order. for &node_index in self.order.as_ref().unwrap().iter() { - if let Some(source_node) = self.vertex[node_index].source_vertex { + if let Some((source_node, source_port)) = self.vertex[node_index].source_vertex { // We can source inputs directly from a source vertex. let ptr = &mut self.vertex[source_node].output as *mut BufferVec; let vertex = &mut self.vertex[node_index]; @@ -1039,7 +1047,7 @@ impl AudioUnit for Net { unsafe { vertex.unit.process( size, - &(*ptr).buffer_ref(), + &(*ptr).buffer_ref().subset(source_port, vertex.inputs()), &mut vertex.output.buffer_mut(), ); } diff --git a/tests/test_basic.rs b/tests/test_basic.rs index 542cb29..b8471fd 100644 --- a/tests/test_basic.rs +++ b/tests/test_basic.rs @@ -266,6 +266,15 @@ fn test_basic() { check_wave((noise() | envelope(|t| spline_noise(1, t * 10.0))) >> panner()); check_wave(impulse::()); + let dc42 = Net::wrap(Box::new(dc(42.))); + let dcs = dc42.clone() | dc42; + let reverb = Net::wrap(Box::new(reverb_stereo(40., 5., 1.))); + let filter = Net::wrap(Box::new(lowpass_hz(1729., 1.))); + let filters = filter.clone() | filter; + let net = dcs >> reverb >> filters; + net.check(); + check_wave(net); + // Wave filtering, tick vs. process rendering, node reseting. let input = Wave::render(44100.0, 1.0, &mut (noise() | noise())); check_wave_filter(&input, butterpass_hz(1000.0) | lowpole_hz(100.0));