WIP: mod amounts in NodeProg

This commit is contained in:
Weird Constructor 2021-07-06 19:55:03 +02:00
parent 196d094673
commit b932b55a8d
3 changed files with 150 additions and 29 deletions

View file

@ -3,6 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
pub const MAX_ALLOCATED_NODES : usize = 256; pub const MAX_ALLOCATED_NODES : usize = 256;
pub const MAX_INPUTS : usize = 32;
pub const MAX_SMOOTHERS : usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs pub const MAX_SMOOTHERS : usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs
pub const MAX_AVAIL_TRACKERS : usize = 128; pub const MAX_AVAIL_TRACKERS : usize = 128;
pub const MAX_FB_DELAYS : usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM pub const MAX_FB_DELAYS : usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM

View file

@ -7,6 +7,7 @@ use super::{
NodeProg, NodeOp, NodeProg, NodeOp,
FeedbackFilter, FeedbackFilter,
MAX_ALLOCATED_NODES, MAX_ALLOCATED_NODES,
MAX_INPUTS,
MAX_AVAIL_TRACKERS, MAX_AVAIL_TRACKERS,
UNUSED_MONITOR_IDX UNUSED_MONITOR_IDX
}; };
@ -40,20 +41,32 @@ pub struct NodeInstance {
in_end: usize, in_end: usize,
at_start: usize, at_start: usize,
at_end: usize, at_end: usize,
mod_start: usize,
mod_end: usize,
/// A mapping array, to map from input index of the node
/// to the modulator index. Because not every input has an
/// associated modulator.
/// This is used later to send [QuickMessage::ModamtUpdate].
/// The input index into this array is the index returned from
/// routines like [NodeId::inp_param].
in2mod_map: [Option<usize>; MAX_INPUTS],
} }
impl NodeInstance { 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_end: 0,
in2mod_map: [None; MAX_INPUTS],
} }
} }
@ -66,10 +79,18 @@ impl NodeInstance {
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),
inputs: vec![], inputs: vec![],
} }
} }
pub fn mod_in_local2global(&self, idx: u8) -> Option<usize> {
if idx > self.in2mod_map.len() {
return None;
}
self.in2mod_map[idx as usize]
}
pub fn in_local2global(&self, idx: u8) -> Option<usize> { pub fn in_local2global(&self, idx: u8) -> Option<usize> {
let idx = self.in_start + idx as usize; let idx = self.in_start + idx as usize;
if idx < self.in_end { Some(idx) } if idx < self.in_end { Some(idx) }
@ -82,24 +103,35 @@ impl NodeInstance {
else { None } else { None }
} }
pub fn set_index(mut self, idx: usize) -> Self { pub fn set_index(&mut self, idx: usize) -> &mut Self {
self.prog_idx = idx; self.prog_idx = idx;
self self
} }
pub fn set_output(mut self, s: usize, e: usize) -> Self { pub fn set_output(&mut self, s: usize, e: usize) -> &mut Self {
self.out_start = s; self.out_start = s;
self.out_end = e; self.out_end = e;
self self
} }
pub fn set_input(mut self, s: usize, e: usize) -> Self { pub fn set_input(&mut self, s: usize, e: usize) -> &mut Self {
self.in_start = s; self.in_start = s;
self.in_end = e; self.in_end = e;
self self
} }
pub fn set_atom(mut self, s: usize, e: usize) -> Self { pub fn set_mod(&mut self, s: usize, e: usize) -> &mut Self {
self.mod_start = s;
self.mod_end = e;
self
}
pub fn set_mod_idx(&mut self, idx: u8, i: usize) -> &mut Self {
self.in2mod_map[idx as usize] = Some(i);
self
}
pub fn set_atom(&mut self, s: usize, e: usize) -> &mut Self {
self.at_start = s; self.at_start = s;
self.at_end = e; self.at_end = e;
self self
@ -111,6 +143,7 @@ struct NodeInputParam {
param_id: ParamId, param_id: ParamId,
input_idx: usize, input_idx: usize,
value: f32, value: f32,
modamt: Option<f32>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -128,27 +161,27 @@ struct NodeInputAtom {
/// as facade for the executed node graph in the backend. /// as facade for the executed node graph in the backend.
pub struct NodeConfigurator { pub struct NodeConfigurator {
/// Holds all the nodes, their parameters and type. /// Holds all the nodes, their parameters and type.
pub(crate) nodes: Vec<(NodeInfo, Option<NodeInstance>)>, pub(crate) nodes: Vec<(NodeInfo, Option<NodeInstance>)>,
/// An index of all nodes ever instanciated. /// An index of all nodes ever instanciated.
/// Be aware, that currently there is no cleanup implemented. /// Be aware, that currently there is no cleanup implemented.
/// That means, any instanciated NodeId will persist throughout /// That means, any instanciated NodeId will persist throughout
/// the whole runtime. A garbage collector might be implemented /// the whole runtime. A garbage collector might be implemented
/// when saving presets. /// when saving presets.
pub(crate) node2idx: HashMap<NodeId, usize>, pub(crate) node2idx: HashMap<NodeId, usize>,
/// Holding the tracker sequencers /// Holding the tracker sequencers
pub(crate) trackers: Vec<Tracker>, pub(crate) trackers: Vec<Tracker>,
/// The shared parts of the [NodeConfigurator] /// The shared parts of the [NodeConfigurator]
/// and the [crate::nodes::NodeExecutor]. /// and the [crate::nodes::NodeExecutor].
pub(crate) shared: SharedNodeConf, pub(crate) shared: SharedNodeConf,
feedback_filter: FeedbackFilter, feedback_filter: FeedbackFilter,
/// Loads and Caches audio samples that are set as parameters /// Loads and Caches audio samples that are set as parameters
/// for nodes. /// for nodes.
sample_lib: SampleLibrary, sample_lib: SampleLibrary,
/// Error messages: /// Error messages:
errors: Vec<String>, errors: Vec<String>,
/// Contains (automateable) parameters /// Contains (automateable) parameters
params: std::collections::HashMap<ParamId, NodeInputParam>, params: std::collections::HashMap<ParamId, NodeInputParam>,
@ -311,6 +344,13 @@ impl NodeConfigurator {
return false; return false;
} }
let mut input_idx = None;
if let Some(nparam) = self.params.get_mut(&param) {
input_idx = Some(nparam.input_idx);
nparam.modamt = v;
}
// Check if the modulation amount was already set, if not, we need // Check if the modulation amount was already set, if not, we need
// to reconstruct the graph and upload an updated NodeProg. // to reconstruct the graph and upload an updated NodeProg.
if let Some(_old_modamt) = if let Some(_old_modamt) =
@ -322,11 +362,9 @@ impl NodeConfigurator {
} else { } else {
let modamt = v.unwrap(); let modamt = v.unwrap();
self.param_modamt.insert(param, v); self.param_modamt.insert(param, v);
if let Some(nparam) = self.params.get_mut(&param) { if let Some(input_idx) = input_idx {
let input_idx = nparam.input_idx;
let _ = let _ =
self.shared.quick_update_prod.push( self.shared.quick_update_prod.push(
QuickMessage::ModamtUpdate { QuickMessage::ModamtUpdate {
@ -744,6 +782,7 @@ impl NodeConfigurator {
let mut out_len = 0; let mut out_len = 0;
let mut in_len = 0; let mut in_len = 0;
let mut at_len = 0; let mut at_len = 0;
let mut mod_len = 0;
for (i, (node_info, node_instance)) for (i, (node_info, node_instance))
in self.nodes.iter_mut().enumerate() in self.nodes.iter_mut().enumerate()
@ -823,7 +862,7 @@ impl NodeConfigurator {
} }
} }
NodeProg::new(out_len, in_len, at_len) NodeProg::new(out_len, in_len, at_len, mod_len)
} }
/// Creates a new [NodeOp] and add it to the [NodeProg]. /// Creates a new [NodeOp] and add it to the [NodeProg].

View file

@ -5,6 +5,76 @@
use crate::dsp::{ProcBuf, SAtom}; use crate::dsp::{ProcBuf, SAtom};
use triple_buffer::{Input, Output, TripleBuffer}; use triple_buffer::{Input, Output, TripleBuffer};
#[derive(Debug, Clone, Copy)]
pub enum ModOpSigRange {
Unipolar,
Bipolar,
}
#[derive(Debug, Clone)]
pub struct ModOp {
amount: f32,
range: ModOpSigRange,
modbuf: ProcBuf,
outbuf: ProcBuf,
inbuf: ProcBuf,
}
impl Drop for ModOp {
fn drop(&mut self) {
self.modbuf.free();
}
}
impl ModOp {
pub fn new() -> Self {
Self {
range: ModOpSigRange::Unipolar,
amount: 0.0,
modbuf: ProcBuf::new(),
outbuf: ProcBuf::null(),
inbuf: ProcBuf::null(),
}
}
pub fn lock(&mut self, inbuf: ProcBuf, outbuf: ProcBuf) {
self.inbuf = inbuf;
self.outbuf = outbuf;
}
pub fn unlock(&mut self) {
self.outbuf = ProcBuf::null();
self.inbuf = ProcBuf::null();
}
#[inline]
pub fn process(&mut self, nframes: usize) {
let modbuf = &mut self.inbuf;
let inbuf = &mut self.inbuf;
let outbuf = &mut self.outbuf;
match self.range {
ModOpSigRange::Bipolar => {
for frame in 0..nframes {
modbuf.write(frame,
modbuf.read(frame)
* ((outbuf.read(frame) + 1.0) * 0.5)
.clamp(0.0, 1.0)
+ inbuf.read(frame));
}
},
ModOpSigRange::Unipolar => {
for frame in 0..nframes {
modbuf.write(frame,
modbuf.read(frame)
* outbuf.read(frame).clamp(0.0, 1.0)
+ inbuf.read(frame));
}
},
}
}
}
/// Step in a `NodeProg` that stores the to be /// Step in a `NodeProg` that stores the to be
/// executed node and output operations. /// executed node and output operations.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -17,6 +87,8 @@ pub struct NodeOp {
pub in_idxlen: (usize, usize), pub in_idxlen: (usize, usize),
/// Atom data index and length of the node: /// Atom data index and length of the node:
pub at_idxlen: (usize, usize), pub at_idxlen: (usize, usize),
/// ModOp index and length of the node:
pub mod_idxlen: (usize, usize),
/// Input indices, (<out vec index>, <own node input index>) /// Input indices, (<out vec index>, <own node input index>)
pub inputs: Vec<(usize, usize)>, pub inputs: Vec<(usize, usize)>,
} }
@ -68,6 +140,9 @@ pub struct NodeProg {
/// vector. /// vector.
pub prog: Vec<NodeOp>, pub prog: Vec<NodeOp>,
/// The modulators for the input parameters.
pub modops: Vec<ModOp>,
/// A marker, that checks if we can still swap buffers with /// A marker, that checks if we can still swap buffers with
/// with other NodeProg instances. This is usally set if the ProcBuf pointers /// with other NodeProg instances. This is usally set if the ProcBuf pointers
/// have been copied into `cur_inp`. You can call `unlock_buffers` to /// have been copied into `cur_inp`. You can call `unlock_buffers` to
@ -107,13 +182,14 @@ impl NodeProg {
params: vec![], params: vec![],
atoms: vec![], atoms: vec![],
prog: vec![], prog: vec![],
modops: vec![],
out_feedback: input_fb, out_feedback: input_fb,
out_fb_cons: Some(output_fb), out_fb_cons: Some(output_fb),
locked_buffers: false, locked_buffers: false,
} }
} }
pub fn new(out_len: usize, inp_len: usize, at_len: usize) -> Self { pub fn new(out_len: usize, inp_len: usize, at_len: usize, mod_len: usize) -> Self {
let mut out = vec![]; let mut out = vec![];
out.resize_with(out_len, ProcBuf::new); out.resize_with(out_len, ProcBuf::new);
@ -130,6 +206,8 @@ impl NodeProg {
params.resize(inp_len, 0.0); params.resize(inp_len, 0.0);
let mut atoms = vec![]; let mut atoms = vec![];
atoms.resize(at_len, SAtom::setting(0)); atoms.resize(at_len, SAtom::setting(0));
let mut modops = vec![];
modops.resize_with(mod_len, ModOp::new);
Self { Self {
out, out,
@ -137,6 +215,7 @@ impl NodeProg {
cur_inp, cur_inp,
params, params,
atoms, atoms,
modops,
prog: vec![], prog: vec![],
out_feedback: input_fb, out_feedback: input_fb,
out_fb_cons: Some(output_fb), out_fb_cons: Some(output_fb),
@ -156,6 +235,10 @@ impl NodeProg {
&mut self.atoms &mut self.atoms
} }
pub fn modops_mut(&mut self) -> &mut [ModOp] {
&mut self.modops
}
pub fn append_op(&mut self, node_op: NodeOp) { pub fn append_op(&mut self, 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 {
@ -164,11 +247,6 @@ impl NodeProg {
} }
self.prog.push(node_op); self.prog.push(node_op);
// TODO: MOD AMOUNT:
// self.mods.push(Option<Vec<(f32, sigtype,
// ProcBuf,
// ProcBuf,
// ProcBuf)>>)
} }
// TODO: MOD AMOUNT CHANGE: // TODO: MOD AMOUNT CHANGE:
@ -220,6 +298,9 @@ impl NodeProg {
for buf in self.cur_inp.iter_mut() { for buf in self.cur_inp.iter_mut() {
*buf = ProcBuf::null(); *buf = ProcBuf::null();
} }
for modop in self.modops.iter_mut() {
modop.unlock();
}
self.locked_buffers = false; self.locked_buffers = false;
} }