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));
|
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]
|
||||||
|
|
|
@ -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], },
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(¶m) {
|
if let Some(nparam) = self.params.get_mut(¶m) {
|
||||||
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,12 +373,17 @@ 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 {
|
||||||
let _ =
|
if let Some(mod_idx) = mod_idx {
|
||||||
self.shared.quick_update_prod.push(
|
let _ =
|
||||||
QuickMessage::ModamtUpdate {
|
self.shared.quick_update_prod.push(
|
||||||
input_idx, modamt
|
QuickMessage::ModamtUpdate {
|
||||||
});
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// - save offset and length of each node's
|
||||||
// allocation in the output vector.
|
// allocation in the output vector.
|
||||||
*node_instance = Some(
|
*node_instance = Some(ni);
|
||||||
NodeInstance::new(id)
|
|
||||||
.set_index(i)
|
|
||||||
.set_output(out_idx, out_len)
|
|
||||||
.set_input(in_idx, in_len)
|
|
||||||
.set_atom(at_idx, at_len));
|
|
||||||
|
|
||||||
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(¶m_id) {
|
if let Some(value) = self.param_values.get(¶m_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(¶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.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.
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue