Implemented a bitmask to enable nodes to not produce output if it is not used.

This commit is contained in:
Weird Constructor 2021-07-10 21:27:18 +02:00
parent 967535d771
commit 26830e8e56
19 changed files with 218 additions and 73 deletions

View file

@ -76,6 +76,18 @@ pub const MIDI_MAX_FREQ : f32 = 13289.75;
pub const MAX_BLOCK_SIZE : usize = 128; pub const MAX_BLOCK_SIZE : usize = 128;
/// A context structure that holds temporary information about the
/// currently executed node.
/// This structure is created by the [crate::nodes::NodeExecutor] on the fly.
pub struct NodeContext<'a> {
/// The bitmask that indicates which output ports are used/connected
/// to some input.
pub out_connected: u64,
/// The node parameters, which are usually not accessed directly.
pub params: &'a [ProcBuf],
}
/// This trait is an interface between the graph functions /// This trait is an interface between the graph functions
/// and the AtomDataModel of the UI. /// and the AtomDataModel of the UI.
pub trait GraphAtomData { pub trait GraphAtomData {
@ -116,8 +128,9 @@ pub trait DspNode {
/// * `outputs` are the output buffers of this node. /// * `outputs` are the output buffers of this node.
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, ectx: &mut NodeExecContext, &mut self, ctx: &mut T, ectx: &mut NodeExecContext,
atoms: &[SAtom], params: &[ProcBuf], inputs: &[ProcBuf], nctx: &NodeContext,
outputs: &mut [ProcBuf], led: LedPhaseVals); atoms: &[SAtom], inputs: &[ProcBuf], outputs: &mut [ProcBuf],
led: LedPhaseVals);
/// A function factory for generating a graph for the generic node UI. /// A function factory for generating a graph for the generic node UI.
fn graph_fun() -> Option<GraphFun> { None } fn graph_fun() -> Option<GraphFun> { None }
@ -564,7 +577,11 @@ macro_rules! node_list {
{1 0 p param(0.0) fa_test_s 0 10} {1 0 p param(0.0) fa_test_s 0 10}
{2 1 trig param(0.0) fa_test_s 0 0} {2 1 trig param(0.0) fa_test_s 0 0}
[0 sig] [0 sig]
[1 tsig], [1 tsig]
[2 out2]
[3 out3]
[4 out4]
[5 outc],
} }
} }
} }
@ -1119,6 +1136,15 @@ macro_rules! make_node_info_enum {
})+ })+
} }
#[allow(non_snake_case)]
pub mod out_buf {
$(pub mod $variant {
$(#[inline] pub fn $out(outputs: &mut [crate::dsp::ProcBuf]) -> crate::dsp::ProcBuf {
outputs[$out_idx]
})*
})+
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub mod out_idx { pub mod out_idx {
$(pub mod $variant { $(pub mod $variant {
@ -1126,6 +1152,15 @@ macro_rules! make_node_info_enum {
})+ })+
} }
#[allow(non_snake_case)]
pub mod is_out_con {
$(pub mod $variant {
$(#[inline] pub fn $out(nctx: &crate::dsp::NodeContext) -> bool {
nctx.out_connected & (1 << $out_idx) != 0x0
})*
})+
}
mod ni { mod ni {
$( $(
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -1441,8 +1476,8 @@ impl Node {
#[inline] #[inline]
pub fn process<T: NodeAudioContext>( pub fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, ectx: &mut NodeExecContext, &mut self, ctx: &mut T, ectx: &mut NodeExecContext,
atoms: &[SAtom], params: &[ProcBuf], nctx: &NodeContext,
inputs: &[ProcBuf], outputs: &mut [ProcBuf], atoms: &[SAtom], inputs: &[ProcBuf], outputs: &mut [ProcBuf],
led: LedPhaseVals) led: LedPhaseVals)
{ {
macro_rules! make_node_process { macro_rules! make_node_process {
@ -1462,7 +1497,7 @@ impl Node {
match self { match self {
Node::$v1 => {}, Node::$v1 => {},
$(Node::$variant { node } => $(Node::$variant { node } =>
node.process(ctx, ectx, atoms, params, node.process(ctx, ectx, nctx, atoms,
inputs, outputs, led),)+ inputs, outputs, led),)+
} }
} }

View file

@ -5,7 +5,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{ use crate::dsp::{
NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals,
GraphAtomData, GraphFun, GraphAtomData, GraphFun, NodeContext,
}; };
use super::helpers::{Trigger, TrigSignal, sqrt4_to_pow4}; use super::helpers::{Trigger, TrigSignal, sqrt4_to_pow4};
@ -120,7 +120,8 @@ impl DspNode for Ad {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, denorm, at}; use crate::dsp::{out, inp, denorm, at};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::helpers::AllPass; use crate::dsp::helpers::AllPass;
/// A simple amplifier /// A simple amplifier
@ -82,7 +82,8 @@ impl DspNode for AllP {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
_atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
_atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, denorm}; use crate::dsp::{out, inp, denorm};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
#[macro_export] #[macro_export]
macro_rules! fa_amp_neg_att { ($formatter: expr, $v: expr, $denorm_v: expr) => { { macro_rules! fa_amp_neg_att { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -71,7 +71,8 @@ impl DspNode for Amp {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, denorm, denorm_v, inp_dir, at}; use crate::dsp::{out, inp, denorm, denorm_v, inp_dir, at};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::helpers::{DelayBuffer, crossfade, TriggerSampleClock}; use crate::dsp::helpers::{DelayBuffer, crossfade, TriggerSampleClock};
#[macro_export] #[macro_export]
@ -91,7 +91,8 @@ impl DspNode for Delay {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{at, out, inp, denorm}; use crate::dsp::{at, out, inp, denorm};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
/// A simple amplifier /// A simple amplifier
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -54,7 +54,8 @@ impl DspNode for FbWr {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, ectx: &mut NodeExecContext, &mut self, ctx: &mut T, ectx: &mut NodeExecContext,
_atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
_atoms: &[SAtom], inputs: &[ProcBuf],
_outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) _outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{inp}; use crate::dsp::{inp};
@ -126,7 +127,8 @@ impl DspNode for FbRd {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, ectx: &mut NodeExecContext, &mut self, ctx: &mut T, ectx: &mut NodeExecContext,
_atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
_atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, denorm}; use crate::dsp::{out, inp, denorm};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
#[macro_export] #[macro_export]
macro_rules! fa_map_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { { macro_rules! fa_map_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -91,7 +91,8 @@ impl DspNode for Map {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, at}; use crate::dsp::{out, inp, at};

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::helpers::Rng; use crate::dsp::helpers::Rng;
#[macro_export] #[macro_export]
@ -84,7 +84,8 @@ impl DspNode for Noise {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{at, out, inp, denorm}; use crate::dsp::{at, out, inp, denorm};

View file

@ -3,7 +3,8 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, inp, at, denorm, DspNode, LedPhaseVals}; use crate::dsp::{
NodeId, SAtom, ProcBuf, inp, at, denorm, DspNode, LedPhaseVals, NodeContext};
#[macro_export] #[macro_export]
macro_rules! fa_out_mono { ($formatter: expr, $v: expr, $denorm_v: expr) => { { macro_rules! fa_out_mono { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -81,7 +82,8 @@ impl DspNode for Out {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
_outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) _outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
let in1 = inp::Out::ch1(inputs); let in1 = inp::Out::ch1(inputs);

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::{out, at, inp, denorm, denorm_offs}; //, inp, denorm, denorm_v, inp_dir, at}; use crate::dsp::{out, at, inp, denorm, denorm_offs}; //, inp, denorm, denorm_v, inp_dir, at};
use super::helpers::Trigger; use super::helpers::Trigger;
@ -370,7 +370,8 @@ impl DspNode for Sampl {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
let sample = at::Sampl::sample(atoms); let sample = at::Sampl::sample(atoms);

View file

@ -5,7 +5,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{ use crate::dsp::{
NodeId, SAtom, ProcBuf, denorm_offs, NodeId, SAtom, ProcBuf, denorm_offs,
out, inp, DspNode, LedPhaseVals out, inp, DspNode, LedPhaseVals, NodeContext
}; };
use crate::dsp::helpers::fast_sin; use crate::dsp::helpers::fast_sin;
@ -76,7 +76,8 @@ impl DspNode for Sin {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
_atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
_atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
let o = out::Sin::sig(outputs); let o = out::Sin::sig(outputs);

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
#[macro_export] #[macro_export]
macro_rules! fa_smap_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { { macro_rules! fa_smap_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -98,7 +98,8 @@ impl DspNode for SMap {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, at}; use crate::dsp::{out, inp, at};

View file

@ -3,7 +3,10 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals}; use crate::dsp::{
NodeId, SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals,
NodeContext
};
use crate::dsp::helpers::{TrigSignal}; use crate::dsp::helpers::{TrigSignal};
#[macro_export] #[macro_export]
@ -46,6 +49,10 @@ impl Test {
pub const trig: &'static str = "Test trig\nA trigger input, that will create a short pulse on the 'tsig' output.\nRange: (-1..1)"; pub const trig: &'static str = "Test trig\nA trigger input, that will create a short pulse on the 'tsig' output.\nRange: (-1..1)";
pub const sig : &'static str = "Test sig\nThe output of p as signal"; pub const sig : &'static str = "Test sig\nThe output of p as signal";
pub const tsig : &'static str = "Test tsig\nA short trigger pulse will be generated when the 'trig' input is triggered."; pub const tsig : &'static str = "Test tsig\nA short trigger pulse will be generated when the 'trig' input is triggered.";
pub const out2 : &'static str = "Test out2\nA test output that will emit 1.0 if output 'sig' is connected.";
pub const out3 : &'static str = "Test out3\n";
pub const out4 : &'static str = "Test out4\n";
pub const outc : &'static str = "Test outc\nEmits a number that defines the out_connected bitmask. Used only for testing!";
pub const DESC : &'static str = r#""#; pub const DESC : &'static str = r#""#;
pub const HELP : &'static str = r#""#; pub const HELP : &'static str = r#""#;
@ -66,14 +73,18 @@ impl DspNode for Test {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], _inputs: &[ProcBuf], nctx: &NodeContext,
atoms: &[SAtom], _inputs: &[ProcBuf],
outputs: &mut [ProcBuf], _led: LedPhaseVals) outputs: &mut [ProcBuf], _led: LedPhaseVals)
{ {
use crate::dsp::{out_idx, at}; use crate::dsp::{out_idx, at, is_out_con, out_buf};
let p = at::Test::p(atoms); let p = at::Test::p(atoms);
let trig = at::Test::trig(atoms); let trig = at::Test::trig(atoms);
let tsig = out_idx::Test::tsig(); let tsig = out_idx::Test::tsig();
let mut out2 = out_buf::Test::out2(outputs);
let mut outc = out_buf::Test::outc(outputs);
let (out, tsig) = outputs.split_at_mut(tsig); let (out, tsig) = outputs.split_at_mut(tsig);
let out = &mut out[0]; let out = &mut out[0];
@ -99,6 +110,10 @@ impl DspNode for Test {
out.write(frame, p.f()); out.write(frame, p.f());
let t = self.trig_sig.next(); let t = self.trig_sig.next();
tsig.write(frame, t); tsig.write(frame, t);
out2.write(frame,
if is_out_con::Test::sig(nctx) { 1.0 } else { 0.0 });
outc.write(frame, nctx.out_connected as f32);
} }
} }

View file

@ -4,7 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::helpers::{TriggerPhaseClock, Trigger}; use crate::dsp::helpers::{TriggerPhaseClock, Trigger};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::tracker::TrackerBackend; use crate::dsp::tracker::TrackerBackend;
use crate::dsp::MAX_BLOCK_SIZE; use crate::dsp::MAX_BLOCK_SIZE;
@ -180,7 +180,8 @@ impl DspNode for TSeq {
#[inline] #[inline]
fn process<T: NodeAudioContext>( fn process<T: NodeAudioContext>(
&mut self, ctx: &mut T, _ectx: &mut NodeExecContext, &mut self, ctx: &mut T, _ectx: &mut NodeExecContext,
atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], _nctx: &NodeContext,
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, at, denorm}; use crate::dsp::{out, inp, at, denorm};

View file

@ -1054,9 +1054,9 @@ mod tests {
assert!(nodes[2].to_id(2) == NodeId::Sin(2)); assert!(nodes[2].to_id(2) == NodeId::Sin(2));
let prog = node_exec.get_prog(); let prog = node_exec.get_prog();
assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1) in=(0-2) at=(0-0) mod=(0-0))"); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2) at=(0-0) mod=(0-0))");
assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2) in=(2-4) at=(0-0) mod=(0-0) cpy=(o0 => i2))"); assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2|1) in=(2-4) at=(0-0) mod=(0-0) cpy=(o0 => i2))");
assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3) in=(4-6) at=(0-0) mod=(0-0) cpy=(o1 => i4))"); assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3|0) in=(4-6) at=(0-0) mod=(0-0) cpy=(o1 => i4))");
} }
#[test] #[test]
@ -1146,8 +1146,8 @@ mod tests {
let prog = node_exec.get_prog(); let prog = node_exec.get_prog();
assert_eq!(prog.prog.len(), 2); assert_eq!(prog.prog.len(), 2);
assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1) in=(0-2) at=(0-0) mod=(0-0))"); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2) at=(0-0) mod=(0-0))");
assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-1) in=(2-5) at=(0-1) mod=(0-0) cpy=(o0 => i2))"); assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-1|0) in=(2-5) at=(0-1) mod=(0-0) cpy=(o0 => i2))");
} }
#[test] #[test]
@ -1177,8 +1177,8 @@ mod tests {
let prog = node_exec.get_prog(); let prog = node_exec.get_prog();
assert_eq!(prog.prog.len(), 2); assert_eq!(prog.prog.len(), 2);
assert_eq!(prog.prog[0].to_string(), "Op(i=2 out=(2-3) in=(4-6) at=(0-0) mod=(0-0))"); assert_eq!(prog.prog[0].to_string(), "Op(i=2 out=(2-3|1) in=(4-6) at=(0-0) mod=(0-0))");
assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-3) in=(6-9) at=(0-1) mod=(0-0) cpy=(o2 => i6))"); assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-3|0) in=(6-9) at=(0-1) mod=(0-0) cpy=(o2 => i6))");
} }
#[test] #[test]
@ -1278,10 +1278,10 @@ mod tests {
node_exec.process_graph_updates(); node_exec.process_graph_updates();
let prog = node_exec.get_prog(); let prog = node_exec.get_prog();
assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1) in=(0-2) at=(0-0) mod=(0-1))"); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2) at=(0-0) mod=(0-1))");
assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-4) in=(6-8) at=(0-0) mod=(5-5))"); assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-4|1) in=(6-8) at=(0-0) mod=(5-5))");
assert_eq!(prog.prog[2].to_string(), "Op(i=1 out=(1-2) in=(2-4) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)"); assert_eq!(prog.prog[2].to_string(), "Op(i=1 out=(1-2|1) in=(2-4) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)");
assert_eq!(prog.prog[3].to_string(), "Op(i=2 out=(2-3) in=(4-6) at=(0-0) mod=(3-5) cpy=(o1 => i4) cpy=(o3 => i5) mod=3 mod=4)"); assert_eq!(prog.prog[3].to_string(), "Op(i=2 out=(2-3|0) in=(4-6) at=(0-0) mod=(3-5) cpy=(o1 => i4) cpy=(o3 => i5) mod=3 mod=4)");
} }
#[test] #[test]
@ -1315,8 +1315,8 @@ mod tests {
node_exec.process_graph_updates(); node_exec.process_graph_updates();
let prog = node_exec.get_prog(); let prog = node_exec.get_prog();
assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1) in=(0-2) at=(0-0) mod=(0-1))"); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2) at=(0-0) mod=(0-1))");
assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2) in=(2-4) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)"); assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2|1) in=(2-4) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)");
assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3) in=(4-6) at=(0-0) mod=(3-3) cpy=(o1 => i4))"); assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3|0) in=(4-6) at=(0-0) mod=(3-3) cpy=(o1 => i4))");
} }
} }

View file

@ -56,17 +56,17 @@ impl NodeInstance {
pub fn new(id: NodeId) -> Self { pub fn new(id: NodeId) -> Self {
Self { Self {
id, id,
in_use: false, in_use: false,
prog_idx: 0, prog_idx: 0,
out_start: 0, out_start: 0,
out_end: 0, out_end: 0,
in_start: 0, in_start: 0,
in_end: 0, in_end: 0,
at_start: 0, at_start: 0,
at_end: 0, at_end: 0,
mod_start: 0, mod_start: 0,
mod_end: 0, mod_end: 0,
in2mod_map: [None; MAX_INPUTS], in2mod_map: [None; MAX_INPUTS],
} }
} }
@ -75,12 +75,13 @@ impl NodeInstance {
pub fn as_op(&self) -> NodeOp { pub fn as_op(&self) -> NodeOp {
NodeOp { NodeOp {
idx: self.prog_idx as u8, idx: self.prog_idx as u8,
out_idxlen: (self.out_start, self.out_end), out_idxlen: (self.out_start, self.out_end),
in_idxlen: (self.in_start, self.in_end), in_idxlen: (self.in_start, self.in_end),
at_idxlen: (self.at_start, self.at_end), at_idxlen: (self.at_start, self.at_end),
mod_idxlen: (self.mod_start, self.mod_end), mod_idxlen: (self.mod_start, self.mod_end),
inputs: vec![], out_connected: 0x0,
inputs: vec![],
} }
} }

View file

@ -7,7 +7,7 @@ use super::{
UNUSED_MONITOR_IDX, MAX_ALLOCATED_NODES, MAX_SMOOTHERS, UNUSED_MONITOR_IDX, MAX_ALLOCATED_NODES, MAX_SMOOTHERS,
MAX_FB_DELAY_SIZE, FB_DELAY_TIME_US MAX_FB_DELAY_SIZE, FB_DELAY_TIME_US
}; };
use crate::dsp::{NodeId, Node, MAX_BLOCK_SIZE}; use crate::dsp::{NodeId, Node, NodeContext, MAX_BLOCK_SIZE};
use crate::util::{Smoother, AtomicFloat}; use crate::util::{Smoother, AtomicFloat};
use crate::monitor::{MonitorBackend, MON_SIG_CNT}; use crate::monitor::{MonitorBackend, MON_SIG_CNT};
@ -447,8 +447,11 @@ impl NodeExecutor {
.process( .process(
ctx, ctx,
exec_ctx, exec_ctx,
&NodeContext {
out_connected: op.out_connected,
params: &prog.inp[inp.0..inp.1],
},
&prog.atoms[at.0..at.1], &prog.atoms[at.0..at.1],
&prog.inp[inp.0..inp.1],
&prog.cur_inp[inp.0..inp.1], &prog.cur_inp[inp.0..inp.1],
&mut prog.out[out.0..out.1], &mut prog.out[out.0..out.1],
&ctx_vals[ctx_idx..ctx_idx + 2]); &ctx_vals[ctx_idx..ctx_idx + 2]);

View file

@ -81,14 +81,34 @@ pub struct NodeOp {
/// (<out vec index>, <own node input index>, /// (<out vec index>, <own node input index>,
/// (<mod index into NodeProg::modops>, <mod amt>)) /// (<mod index into NodeProg::modops>, <mod amt>))
pub inputs: Vec<(usize, usize, Option<usize>)>, pub inputs: Vec<(usize, usize, Option<usize>)>,
/// A bit mask which indicates which of the output ports are actually
/// used/connected to some input.
pub out_connected: u64,
}
impl NodeOp {
pub fn out_idx_belongs_to_nodeop(&self, idx: usize) -> bool {
idx >= self.out_idxlen.0
&& idx < self.out_idxlen.1
}
pub fn set_out_idx_connected_flag(&mut self, global_idx: usize) {
if !self.out_idx_belongs_to_nodeop(global_idx) {
return;
}
let local_idx = global_idx - self.out_idxlen.0;
self.out_connected |= 0x1 << local_idx;
}
} }
impl std::fmt::Display for NodeOp { impl std::fmt::Display for NodeOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Op(i={} out=({}-{}) in=({}-{}) at=({}-{}) mod=({}-{})", write!(f, "Op(i={} out=({}-{}|{:x}) in=({}-{}) at=({}-{}) mod=({}-{})",
self.idx, self.idx,
self.out_idxlen.0, self.out_idxlen.0,
self.out_idxlen.1, self.out_idxlen.1,
self.out_connected,
self.in_idxlen.0, self.in_idxlen.0,
self.in_idxlen.1, self.in_idxlen.1,
self.at_idxlen.0, self.at_idxlen.0,
@ -167,7 +187,6 @@ impl Drop for NodeProg {
} }
} }
impl NodeProg { impl NodeProg {
pub fn empty() -> Self { pub fn empty() -> Self {
let out_fb = vec![]; let out_fb = vec![];
@ -237,13 +256,14 @@ impl NodeProg {
&mut self.modops &mut self.modops
} }
pub fn append_op(&mut self, node_op: NodeOp) { pub fn append_op(&mut self, mut node_op: NodeOp) {
for n_op in self.prog.iter_mut() { for n_op in self.prog.iter_mut() {
if n_op.idx == node_op.idx { if n_op.idx == node_op.idx {
return; return;
} }
} }
node_op.out_connected = 0x0;
self.prog.push(node_op); self.prog.push(node_op);
} }
@ -254,6 +274,12 @@ impl NodeProg {
out_index: usize, out_index: usize,
mod_index: Option<usize>) mod_index: Option<usize>)
{ {
for n_op in self.prog.iter_mut() {
if n_op.out_idx_belongs_to_nodeop(out_index) {
n_op.set_out_idx_connected_flag(out_index);
}
}
for n_op in self.prog.iter_mut() { for n_op in self.prog.iter_mut() {
if n_op.idx == node_op.idx { if n_op.idx == node_op.idx {
n_op.inputs.push((out_index, inp_index, mod_index)); n_op.inputs.push((out_index, inp_index, mod_index));

View file

@ -28,3 +28,54 @@ fn check_node_test_1() {
let res = run_for_ms(&mut node_exec, 1.0); let res = run_for_ms(&mut node_exec, 1.0);
assert_decimated_feq!(res.0, 1, vec![ 0.0; 10 ]); assert_decimated_feq!(res.0, 1, vec![ 0.0; 10 ]);
} }
#[test]
fn check_node_test_out_connected() {
let (node_conf, mut node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 6, 3);
let test = NodeId::Test(0);
let out = NodeId::Out(0);
let sin = NodeId::Sin(0);
let sin2 = NodeId::Sin(1);
let sin3 = NodeId::Sin(2);
matrix.place(0, 0, Cell::empty(test)
.out(None, None, test.out("outc")));
matrix.place(0, 1, Cell::empty(out)
.input(out.inp("ch1"), None, None));
matrix.place(1, 0, Cell::empty(test)
.out(None, None, test.out("out2")));
matrix.place(1, 1, Cell::empty(out)
.input(out.inp("ch2"), None, None));
matrix.place(2, 0, Cell::empty(test)
.out(None, None, test.out("out3")));
matrix.place(2, 1, Cell::empty(sin)
.input(sin.inp("freq"), None, None));
matrix.place(3, 0, Cell::empty(test)
.out(None, None, test.out("out4")));
matrix.place(3, 1, Cell::empty(sin2)
.input(sin2.inp("freq"), None, None));
matrix.place(4, 0, Cell::empty(test)
.out(None, None, test.out("sig")));
matrix.place(4, 1, Cell::empty(sin3)
.input(sin3.inp("freq"), None, None));
matrix.sync().unwrap();
let res = run_for_ms(&mut node_exec, 2.0);
let mask = 0x01 | 0x04 | 0x08 | 0x10 | 0x20;
assert_decimated_feq!(res.0, 1, vec![ mask as f32; 10 ]);
assert_decimated_feq!(res.1, 1, vec![ 1.0; 10 ]);
// Remove a connection for testing:
matrix.place(1, 1, Cell::empty(NodeId::Nop));
matrix.sync().unwrap();
let res = run_for_ms(&mut node_exec, 2.0);
let mask = 0x01 | 0x08 | 0x10 | 0x20;
assert_decimated_feq!(res.0, 1, vec![ mask as f32; 10 ]);
assert_decimated_feq!(res.1, 1, vec![ 0.0; 10 ]);
}