implemented more of the parameter modulation amount
This commit is contained in:
parent
b932b55a8d
commit
5d975c91a4
4 changed files with 132 additions and 45 deletions
|
@ -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]
|
||||
|
|
|
@ -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], },
|
||||
}
|
||||
|
|
|
@ -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(¶m) {
|
||||
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(¶m_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(¶m_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.
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue