implemented more of the parameter modulation amount

This commit is contained in:
Weird Constructor 2021-07-07 05:03:28 +02:00
parent b932b55a8d
commit 5d975c91a4
4 changed files with 132 additions and 45 deletions

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))"); 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[1].to_string(), "Op(i=1 out=(1-2) in=(2-4) at=(0-0) cpy=(o0 => i2))"); 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[2].to_string(), "Op(i=2 out=(2-3) in=(4-6) at=(0-0) cpy=(o1 => i4))"); 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))");
} }
#[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))"); 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[1].to_string(), "Op(i=1 out=(1-1) in=(2-5) at=(0-1) cpy=(o0 => i2))"); 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))");
} }
#[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))"); 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[1].to_string(), "Op(i=3 out=(3-3) in=(6-9) at=(0-1) cpy=(o2 => i6))"); 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))");
} }
#[test] #[test]

View file

@ -56,7 +56,7 @@ pub enum GraphMessage {
pub enum QuickMessage { pub enum QuickMessage {
AtomUpdate { at_idx: usize, value: SAtom }, AtomUpdate { at_idx: usize, value: SAtom },
ParamUpdate { input_idx: usize, value: f32 }, ParamUpdate { input_idx: usize, value: f32 },
ModamtUpdate { input_idx: usize, modamt: f32 }, ModamtUpdate { input_idx: usize, mod_idx: usize, modamt: f32 },
/// Sets the buffer indices to monitor with the FeedbackProcessor. /// Sets the buffer indices to monitor with the FeedbackProcessor.
SetMonitor { bufs: [usize; MON_SIG_CNT], }, SetMonitor { bufs: [usize; MON_SIG_CNT], },
} }

View file

@ -4,7 +4,7 @@
use super::{ use super::{
GraphMessage, QuickMessage, GraphMessage, QuickMessage,
NodeProg, NodeOp, NodeProg, ModOpSigRange, NodeOp,
FeedbackFilter, FeedbackFilter,
MAX_ALLOCATED_NODES, MAX_ALLOCATED_NODES,
MAX_INPUTS, MAX_INPUTS,
@ -85,7 +85,7 @@ impl NodeInstance {
} }
pub fn mod_in_local2global(&self, idx: u8) -> Option<usize> { pub fn mod_in_local2global(&self, idx: u8) -> Option<usize> {
if idx > self.in2mod_map.len() { if (idx as usize) > self.in2mod_map.len() {
return None; return None;
} }
self.in2mod_map[idx as usize] self.in2mod_map[idx as usize]
@ -126,8 +126,12 @@ impl NodeInstance {
self self
} }
pub fn set_mod_idx(&mut self, idx: u8, i: usize) -> &mut Self { /// Sets the modulator index mapping: `idx` is the
self.in2mod_map[idx as usize] = Some(i); /// index of the parameter like in [NodeId::inp_param_by_idx],
/// and `i` is the absolute index of the modulator that belongs
/// to this parameter.
pub fn set_mod_idx(&mut self, idx: usize, i: usize) -> &mut Self {
self.in2mod_map[idx] = Some(i);
self self
} }
@ -143,7 +147,7 @@ struct NodeInputParam {
param_id: ParamId, param_id: ParamId,
input_idx: usize, input_idx: usize,
value: f32, value: f32,
modamt: Option<f32>, modamt: Option<(usize, f32)>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -345,10 +349,15 @@ impl NodeConfigurator {
} }
let mut input_idx = None; let mut input_idx = None;
let mut mod_idx = None;
if let Some(nparam) = self.params.get_mut(&param) { if let Some(nparam) = self.params.get_mut(&param) {
input_idx = Some(nparam.input_idx); input_idx = Some(nparam.input_idx);
nparam.modamt = v;
if let Some(modamt) = &mut nparam.modamt {
mod_idx = Some(modamt.0);
modamt.1 = v.unwrap_or(0.0);
}
} }
// Check if the modulation amount was already set, if not, we need // Check if the modulation amount was already set, if not, we need
@ -364,13 +373,18 @@ impl NodeConfigurator {
let modamt = v.unwrap(); let modamt = v.unwrap();
self.param_modamt.insert(param, v); self.param_modamt.insert(param, v);
// TODO: Check if the ModamtUpdate message really needs
// the input_idx once the NodeExecutor backend
// code for that message has been implemented!
if let Some(input_idx) = input_idx { if let Some(input_idx) = input_idx {
if let Some(mod_idx) = mod_idx {
let _ = let _ =
self.shared.quick_update_prod.push( self.shared.quick_update_prod.push(
QuickMessage::ModamtUpdate { QuickMessage::ModamtUpdate {
input_idx, modamt input_idx, mod_idx, modamt
}); });
} }
}
false false
} }
@ -801,18 +815,22 @@ impl NodeConfigurator {
let at_idx = at_len; let at_idx = at_len;
at_len += node_info.at_count(); at_len += node_info.at_count();
// - hold the mod start index of this node.
let mod_idx = mod_len;
if id == NodeId::Nop { if id == NodeId::Nop {
break; break;
} }
// - save offset and length of each node's let mut ni = NodeInstance::new(id);
// allocation in the output vector. ni.set_index(i)
*node_instance = Some(
NodeInstance::new(id)
.set_index(i)
.set_output(out_idx, out_len) .set_output(out_idx, out_len)
.set_input(in_idx, in_len) .set_input(in_idx, in_len)
.set_atom(at_idx, at_len)); .set_atom(at_idx, at_len);
// - save offset and length of each node's
// allocation in the output vector.
*node_instance = Some(ni);
println!("INSERT[{}]: {:?} outidx: {},{} inidx: {},{} atidx: {},{}", println!("INSERT[{}]: {:?} outidx: {},{} inidx: {},{} atidx: {},{}",
i, id, out_idx, out_len, in_idx, in_len, at_idx, at_len); i, id, out_idx, out_len, in_idx, in_len, at_idx, at_len);
@ -820,7 +838,9 @@ impl NodeConfigurator {
// Create new parameters and initialize them if they did not // Create new parameters and initialize them if they did not
// already exist previously // already exist previously
for param_idx in in_idx..in_len { for param_idx in in_idx..in_len {
if let Some(param_id) = id.inp_param_by_idx(param_idx - in_idx) { let input_idx = param_idx - in_idx;
if let Some(param_id) = id.inp_param_by_idx(input_idx) {
let value = let value =
if let Some(value) = self.param_values.get(&param_id) { if let Some(value) = self.param_values.get(&param_id) {
*value *value
@ -828,15 +848,39 @@ impl NodeConfigurator {
param_id.norm_def() param_id.norm_def()
}; };
// If we have a modulation, store the absolute
// index of it in the [NodeProg::modops] vector later:
let ma = self.param_modamt.get(&param_id).copied().flatten();
let modamt =
if ma.is_some() {
let mod_idx = mod_len;
node_instance
.as_mut()
.unwrap()
.set_mod_idx(input_idx, mod_idx);
mod_len += 1;
Some((mod_idx, ma.unwrap()))
} else {
None
};
self.param_values.insert(param_id, value); self.param_values.insert(param_id, value);
self.params.insert(param_id, NodeInputParam { self.params.insert(param_id, NodeInputParam {
param_id, param_id,
value, value,
input_idx: param_idx, input_idx: param_idx,
modamt,
}); });
} }
} }
// After iterating through the parameters we can
// store the range of the indices of this node.
node_instance
.as_mut()
.unwrap()
.set_mod(mod_idx, mod_len);
// Create new atom data and initialize it if it did not // Create new atom data and initialize it if it did not
// already exist from a previous matrix instance. // already exist from a previous matrix instance.
for atom_idx in at_idx..at_len { for atom_idx in at_idx..at_len {
@ -910,10 +954,17 @@ impl NodeConfigurator {
let op = node_instance.as_op(); let op = node_instance.as_op();
let input_index = node_instance.in_local2global(node_input.1); let input_index = node_instance.in_local2global(node_input.1);
let mod_index = node_instance.mod_in_local2global(node_input.1);
if let (Some(input_index), Some(output_index)) = if let (Some(input_index), Some(output_index)) =
(input_index, output_index) (input_index, output_index)
{ {
prog.append_edge(op, input_index, output_index); // TODO: Fetch output signal range from adjacent_output!
prog.append_edge(
op,
input_index,
output_index,
mod_index.map(|amt| (amt, ModOpSigRange::Unipolar)));
} }
} }
} }
@ -960,6 +1011,10 @@ impl NodeConfigurator {
// reset the inp[] input value vector. // reset the inp[] input value vector.
for (_param_id, param) in self.params.iter() { for (_param_id, param) in self.params.iter() {
prog.params_mut()[param.input_idx] = param.value; prog.params_mut()[param.input_idx] = param.value;
if let Some((mod_idx, amt)) = param.modamt {
prog.modops_mut()[mod_idx].set_amt(amt);
}
} }
// The atoms are referred to directly on process() call. // The atoms are referred to directly on process() call.

View file

@ -11,6 +11,15 @@ pub enum ModOpSigRange {
Bipolar, Bipolar,
} }
impl std::fmt::Display for ModOpSigRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ModOpSigRange::Unipolar => write!(f, "SigRange::Unipolar"),
ModOpSigRange::Bipolar => write!(f, "SigRange::Bipolar"),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ModOp { pub struct ModOp {
amount: f32, amount: f32,
@ -37,6 +46,14 @@ impl ModOp {
} }
} }
pub fn set_amt(&mut self, amt: f32) {
self.amount = amt;
}
pub fn set_range(&mut self, range: ModOpSigRange) {
self.range = range;
}
pub fn lock(&mut self, inbuf: ProcBuf, outbuf: ProcBuf) { pub fn lock(&mut self, inbuf: ProcBuf, outbuf: ProcBuf) {
self.inbuf = inbuf; self.inbuf = inbuf;
self.outbuf = outbuf; self.outbuf = outbuf;
@ -49,7 +66,7 @@ impl ModOp {
#[inline] #[inline]
pub fn process(&mut self, nframes: usize) { pub fn process(&mut self, nframes: usize) {
let modbuf = &mut self.inbuf; let modbuf = &mut self.modbuf;
let inbuf = &mut self.inbuf; let inbuf = &mut self.inbuf;
let outbuf = &mut self.outbuf; let outbuf = &mut self.outbuf;
@ -89,23 +106,31 @@ pub struct NodeOp {
pub at_idxlen: (usize, usize), pub at_idxlen: (usize, usize),
/// ModOp index and length of the node: /// ModOp index and length of the node:
pub mod_idxlen: (usize, usize), pub mod_idxlen: (usize, usize),
/// Input indices, (<out vec index>, <own node input index>) /// Input indices,
pub inputs: Vec<(usize, usize)>, /// (<out vec index>, <own node input index>,
/// (<mod index into NodeProg::modops>, <mod amt>, <mod sig type>))
pub inputs: Vec<(usize, usize, Option<(usize, f32, ModOpSigRange)>)>,
} }
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=({}-{})", write!(f, "Op(i={} out=({}-{}) in=({}-{}) at=({}-{}) mod=({}-{})",
self.idx, self.idx,
self.out_idxlen.0, self.out_idxlen.0,
self.out_idxlen.1, self.out_idxlen.1,
self.in_idxlen.0, self.in_idxlen.0,
self.in_idxlen.1, self.in_idxlen.1,
self.at_idxlen.0, self.at_idxlen.0,
self.at_idxlen.1)?; self.at_idxlen.1,
self.mod_idxlen.0,
self.mod_idxlen.1)?;
for i in self.inputs.iter() { for i in self.inputs.iter() {
write!(f, " cpy=(o{} => i{})", i.0, i.1)?; write!(f, " cpy=(o{} => i{})", i.0, i.1)?;
if let Some((idx, amt, rng)) = i.2 {
write!(f, " mod=({:6.4}/{} @{})", amt, rng, idx)?;
}
} }
write!(f, ")") write!(f, ")")
@ -249,25 +274,31 @@ impl NodeProg {
self.prog.push(node_op); self.prog.push(node_op);
} }
// TODO: MOD AMOUNT CHANGE:
pub fn append_edge( pub fn append_edge(
&mut self, &mut self,
node_op: NodeOp, node_op: NodeOp,
inp_index: usize, inp_index: usize,
out_index: usize) // mod_amt: Option<(f32, sigtype)> out_index: usize,
mod_amt: Option<(usize, ModOpSigRange)>)
{ {
// If we have a modulation:
// self.mod_bufs.push(ProcBuf::new())
// modbuf_idx = self.mod_bufs.len();
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 if let Some((idx, range)) = mod_amt {
/* Option<(f32, sigtype, modbuf_idx>*/)); self.modops[idx].set_range(range);
}
n_op.inputs.push(
(out_index,
inp_index,
mod_amt.map(|(idx, sigrng)| (idx, 0.0, sigrng))));
return; return;
} }
} }
} }
/// This is called right after the [crate::nodes::NodeExecutor]
/// received this NodeProg from the [crate::nodes::NodeConfigurator].
/// It initializes internal buffers with parameter data.
pub fn initialize_input_buffers(&mut self) { pub fn initialize_input_buffers(&mut self) {
for param_idx in 0..self.params.len() { for param_idx in 0..self.params.len() {
let param_val = self.params[param_idx]; let param_val = self.params[param_idx];
@ -331,14 +362,15 @@ impl NodeProg {
input_bufs[inp.0..inp.1] input_bufs[inp.0..inp.1]
.copy_from_slice(&self.inp[inp.0..inp.1]); .copy_from_slice(&self.inp[inp.0..inp.1]);
// TODO: self.mods.clear() (ProcBufs are in modbufs)
// Second step (assign outputs): // Second step (assign outputs):
for io in op.inputs.iter() { for io in op.inputs.iter() {
// TODO: MOD AMOUNT: take from mod_bufs assign to input_bufs,
// add entry to self.mods???? we need indices...?!
// Create mods entries which contain all the info for node_exec.
input_bufs[io.1] = out_bufs[io.0]; input_bufs[io.1] = out_bufs[io.0];
if let Some((idx, _, _)) = io.2 {
self.modops[idx].lock(
self.inp[io.1],
out_bufs[io.0]);
}
} }
} }