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));
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[1].to_string(), "Op(i=1 out=(1-2) in=(2-4) at=(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[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) 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))");
}
#[test]
@ -1146,8 +1146,8 @@ mod tests {
let prog = node_exec.get_prog();
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[1].to_string(), "Op(i=1 out=(1-1) in=(2-5) at=(0-1) cpy=(o0 => i2))");
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) mod=(0-0) cpy=(o0 => i2))");
}
#[test]
@ -1177,8 +1177,8 @@ mod tests {
let prog = node_exec.get_prog();
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[1].to_string(), "Op(i=3 out=(3-3) in=(6-9) at=(0-1) cpy=(o2 => i6))");
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) mod=(0-0) cpy=(o2 => i6))");
}
#[test]

View file

@ -56,7 +56,7 @@ pub enum GraphMessage {
pub enum QuickMessage {
AtomUpdate { at_idx: usize, value: SAtom },
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.
SetMonitor { bufs: [usize; MON_SIG_CNT], },
}

View file

@ -4,7 +4,7 @@
use super::{
GraphMessage, QuickMessage,
NodeProg, NodeOp,
NodeProg, ModOpSigRange, NodeOp,
FeedbackFilter,
MAX_ALLOCATED_NODES,
MAX_INPUTS,
@ -85,7 +85,7 @@ impl NodeInstance {
}
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;
}
self.in2mod_map[idx as usize]
@ -126,8 +126,12 @@ impl NodeInstance {
self
}
pub fn set_mod_idx(&mut self, idx: u8, i: usize) -> &mut Self {
self.in2mod_map[idx as usize] = Some(i);
/// Sets the modulator index mapping: `idx` is the
/// 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
}
@ -143,7 +147,7 @@ struct NodeInputParam {
param_id: ParamId,
input_idx: usize,
value: f32,
modamt: Option<f32>,
modamt: Option<(usize, f32)>,
}
#[derive(Debug, Clone)]
@ -345,10 +349,15 @@ impl NodeConfigurator {
}
let mut input_idx = None;
let mut mod_idx = None;
if let Some(nparam) = self.params.get_mut(&param) {
input_idx = Some(nparam.input_idx);
nparam.modamt = v;
input_idx = Some(nparam.input_idx);
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
@ -364,12 +373,17 @@ impl NodeConfigurator {
let modamt = v.unwrap();
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 {
let _ =
self.shared.quick_update_prod.push(
QuickMessage::ModamtUpdate {
input_idx, modamt
});
if let Some(mod_idx) = mod_idx {
let _ =
self.shared.quick_update_prod.push(
QuickMessage::ModamtUpdate {
input_idx, mod_idx, modamt
});
}
}
false
@ -801,18 +815,22 @@ impl NodeConfigurator {
let at_idx = at_len;
at_len += node_info.at_count();
// - hold the mod start index of this node.
let mod_idx = mod_len;
if id == NodeId::Nop {
break;
}
let mut ni = NodeInstance::new(id);
ni.set_index(i)
.set_output(out_idx, out_len)
.set_input(in_idx, in_len)
.set_atom(at_idx, at_len);
// - save offset and length of each node's
// allocation in the output vector.
*node_instance = Some(
NodeInstance::new(id)
.set_index(i)
.set_output(out_idx, out_len)
.set_input(in_idx, in_len)
.set_atom(at_idx, at_len));
*node_instance = Some(ni);
println!("INSERT[{}]: {:?} outidx: {},{} inidx: {},{} atidx: {},{}",
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
// already exist previously
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 =
if let Some(value) = self.param_values.get(&param_id) {
*value
@ -828,15 +848,39 @@ impl NodeConfigurator {
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.params.insert(param_id, NodeInputParam {
param_id,
value,
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
// already exist from a previous matrix instance.
for atom_idx in at_idx..at_len {
@ -910,10 +954,17 @@ impl NodeConfigurator {
let op = node_instance.as_op();
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)) =
(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.
for (_param_id, param) in self.params.iter() {
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.

View file

@ -11,6 +11,15 @@ pub enum ModOpSigRange {
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)]
pub struct ModOp {
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) {
self.inbuf = inbuf;
self.outbuf = outbuf;
@ -49,7 +66,7 @@ impl ModOp {
#[inline]
pub fn process(&mut self, nframes: usize) {
let modbuf = &mut self.inbuf;
let modbuf = &mut self.modbuf;
let inbuf = &mut self.inbuf;
let outbuf = &mut self.outbuf;
@ -89,23 +106,31 @@ pub struct NodeOp {
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>)
pub inputs: Vec<(usize, usize)>,
/// Input indices,
/// (<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 {
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.out_idxlen.0,
self.out_idxlen.1,
self.in_idxlen.0,
self.in_idxlen.1,
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() {
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, ")")
@ -249,25 +274,31 @@ impl NodeProg {
self.prog.push(node_op);
}
// TODO: MOD AMOUNT CHANGE:
pub fn append_edge(
&mut self,
node_op: NodeOp,
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() {
if n_op.idx == node_op.idx {
n_op.inputs.push((out_index, inp_index
/* Option<(f32, sigtype, modbuf_idx>*/));
if let Some((idx, range)) = mod_amt {
self.modops[idx].set_range(range);
}
n_op.inputs.push(
(out_index,
inp_index,
mod_amt.map(|(idx, sigrng)| (idx, 0.0, sigrng))));
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) {
for param_idx in 0..self.params.len() {
let param_val = self.params[param_idx];
@ -331,14 +362,15 @@ impl NodeProg {
input_bufs[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):
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];
if let Some((idx, _, _)) = io.2 {
self.modops[idx].lock(
self.inp[io.1],
out_bufs[io.0]);
}
}
}