storing the modulation amount in the NodeConfigurator / Matrix is now implemented

This commit is contained in:
Weird Constructor 2021-07-06 05:00:34 +02:00
parent b48d423b5a
commit 196d094673
5 changed files with 115 additions and 24 deletions

View file

@ -470,7 +470,7 @@ impl Matrix {
let _ = self.sync();
}
pub fn for_each_atom<F: FnMut(usize, ParamId, &SAtom)>(&self, f: F) {
pub fn for_each_atom<F: FnMut(usize, ParamId, &SAtom, Option<f32>)>(&self, f: F) {
self.config.for_each_param(f);
}
@ -623,6 +623,17 @@ impl Matrix {
self.config.set_param(param, at);
}
/// Assign or remove modulation of an input parameter.
pub fn set_param_modamt(&mut self, param: ParamId, modamt: Option<f32>)
-> Result<(), MatrixError>
{
if self.config.set_param_modamt(param, modamt) {
self.sync()
} else {
Ok(())
}
}
pub fn get_adjacent_output(&self, x: usize, y: usize, dir: CellDir)
-> Option<(NodeId, u8)>
{

View file

@ -142,7 +142,7 @@ impl PatternRepr {
#[derive(Debug, Clone)]
pub struct MatrixRepr {
pub cells: Vec<CellRepr>,
pub params: Vec<(ParamId, f32)>,
pub params: Vec<(ParamId, f32, Option<f32>)>,
pub atoms: Vec<(ParamId, SAtom)>,
pub patterns: Vec<Option<PatternRepr>>,
}
@ -312,7 +312,9 @@ impl MatrixRepr {
if let Some(param_id) = param_id {
m.params.push(
(param_id, v[3].as_f64().unwrap_or(0.0) as f32));
(param_id,
v[3].as_f64().unwrap_or(0.0) as f32,
v[4].as_f64().map(|v| v as f32)));
} else {
return Err(
MatrixDeserError::UnknownParamId(v.to_string()));
@ -358,14 +360,21 @@ impl MatrixRepr {
let mut params = json!([]);
if let Value::Array(params) = &mut params {
for (p, v) in self.params.iter() {
params.push(
json!([
p.node_id().name(),
p.node_id().instance(),
p.name(),
v
]));
for (p, v, ma) in self.params.iter() {
let mut param_v = json!([
p.node_id().name(),
p.node_id().instance(),
p.name(),
v,
]);
if let Value::Array(param_v) = &mut param_v {
if let Some(ma) = ma {
param_v.push(json!(ma));
}
}
params.push(param_v);
}
}

View file

@ -53,10 +53,11 @@ pub enum GraphMessage {
/// and the NodeConfigurator.
#[derive(Debug)]
pub enum QuickMessage {
AtomUpdate { at_idx: usize, value: SAtom },
ParamUpdate { input_idx: usize, value: f32 },
AtomUpdate { at_idx: usize, value: SAtom },
ParamUpdate { input_idx: usize, value: f32 },
ModamtUpdate { input_idx: usize, modamt: f32 },
/// Sets the buffer indices to monitor with the FeedbackProcessor.
SetMonitor { bufs: [usize; MON_SIG_CNT], },
SetMonitor { bufs: [usize; MON_SIG_CNT], },
}
pub const UNUSED_MONITOR_IDX : usize = 99999;

View file

@ -154,6 +154,8 @@ pub struct NodeConfigurator {
params: std::collections::HashMap<ParamId, NodeInputParam>,
/// Stores the most recently set parameter values
param_values: std::collections::HashMap<ParamId, f32>,
/// Stores the modulation amount of a parameter
param_modamt: std::collections::HashMap<ParamId, Option<f32>>,
/// Contains non automateable atom data for the nodes
atoms: std::collections::HashMap<ParamId, NodeInputAtom>,
/// Stores the most recently set atoms
@ -241,6 +243,7 @@ impl NodeConfigurator {
output_fb_cons: None,
params: std::collections::HashMap::new(),
param_values: std::collections::HashMap::new(),
param_modamt: std::collections::HashMap::new(),
atoms: std::collections::HashMap::new(),
atom_values: std::collections::HashMap::new(),
node2idx: HashMap::new(),
@ -299,6 +302,47 @@ impl NodeConfigurator {
self.nodes.get_mut(idx)
}
/// Set the modulation amount of a parameter.
/// Returns true if a new [NodeProg] needs to be created, which can be
/// necessary if there was no modulation amount assigned to this parameter
/// yet.
pub fn set_param_modamt(&mut self, param: ParamId, v: Option<f32>) -> bool {
if param.is_atom() {
return false;
}
// Check if the modulation amount was already set, if not, we need
// to reconstruct the graph and upload an updated NodeProg.
if let Some(_old_modamt) =
self.param_modamt.get(&param).copied().flatten()
{
if v.is_none() {
self.param_modamt.insert(param, v);
true
} else {
let modamt = v.unwrap();
self.param_modamt.insert(param, v);
if let Some(nparam) = self.params.get_mut(&param) {
let input_idx = nparam.input_idx;
let _ =
self.shared.quick_update_prod.push(
QuickMessage::ModamtUpdate {
input_idx, modamt
});
}
false
}
} else {
self.param_modamt.insert(param, v);
true
}
}
/// Assign [SAtom] values to input parameters and atoms.
///
/// Only updates the DSP backend if [NodeConfigurator::rebuild_node_ports] was called
@ -356,12 +400,18 @@ impl NodeConfigurator {
/// Most useful for serialization and saving patches.
#[allow(clippy::type_complexity)]
pub fn dump_param_values(&self)
-> (Vec<(ParamId, f32)>, Vec<(ParamId, SAtom)>)
-> (Vec<(ParamId, f32, Option<f32>)>, Vec<(ParamId, SAtom)>)
{
let params : Vec<(ParamId, f32)> =
let params : Vec<(ParamId, f32, Option<f32>)> =
self.param_values
.iter()
.map(|(param_id, value)| (*param_id, *value))
.map(|(param_id, value)|
(*param_id,
*value,
self.param_modamt
.get(param_id)
.copied()
.flatten()))
.collect();
let atoms : Vec<(ParamId, SAtom)> =
@ -376,10 +426,13 @@ impl NodeConfigurator {
/// Loads parameter values from a dump. You will still need to upload
/// a new [NodeProg] which contains these values.
pub fn load_dumped_param_values(
&mut self, params: &[(ParamId, f32)], atoms: &[(ParamId, SAtom)])
&mut self,
params: &[(ParamId, f32, Option<f32>)],
atoms: &[(ParamId, SAtom)])
{
for (param_id, val) in params.iter() {
for (param_id, val, modamt) in params.iter() {
self.set_param(*param_id, (*val).into());
self.set_param_modamt(*param_id, *modamt);
}
for (param_id, val) in atoms.iter() {
@ -389,12 +442,12 @@ impl NodeConfigurator {
/// Iterates over every parameter and calls the given function with
/// it's current value.
pub fn for_each_param<F: FnMut(usize, ParamId, &SAtom)>(&self, mut f: F) {
pub fn for_each_param<F: FnMut(usize, ParamId, &SAtom, Option<f32>)>(&self, mut f: F) {
for (_, node_input) in self.atoms.iter() {
if let Some(unique_idx) =
self.unique_index_for(&node_input.param_id.node_id())
{
f(unique_idx, node_input.param_id, &node_input.value);
f(unique_idx, node_input.param_id, &node_input.value, None);
}
}
@ -402,8 +455,15 @@ impl NodeConfigurator {
if let Some(unique_idx) =
self.unique_index_for(&node_input.param_id.node_id())
{
let modamt =
self.param_modamt
.get(&node_input.param_id)
.copied()
.flatten();
f(unique_idx, node_input.param_id,
&SAtom::param(node_input.value));
&SAtom::param(node_input.value),
modamt);
}
}
}
@ -513,11 +573,15 @@ impl NodeConfigurator {
/// The monitor data can be retrieved using
/// [NodeConfigurator::get_minmax_monitor_samples].
pub fn monitor(&mut self,
node_id: &NodeId, inputs: &[Option<u8>], outputs: &[Option<u8>])
node_id: &NodeId,
inputs: &[Option<u8>],
outputs: &[Option<u8>])
{
let mut bufs = [UNUSED_MONITOR_IDX; MON_SIG_CNT];
if let Some((_node_info, Some(node_instance))) = self.node_by_id(node_id) {
if let Some((_node_info, Some(node_instance))) =
self.node_by_id(node_id)
{
let mut i = 0;
for inp_idx in inputs.iter().take(MON_SIG_CNT / 2) {
if let Some(inp_idx) = inp_idx {
@ -572,6 +636,7 @@ impl NodeConfigurator {
self.nodes.fill_with(|| (NodeInfo::Nop, None));
self.params .clear();
self.param_values.clear();
self.param_modamt.clear();
self.atoms .clear();
self.atom_values .clear();

View file

@ -398,6 +398,11 @@ impl NodeExecutor {
QuickMessage::ParamUpdate { input_idx, value } => {
self.set_param(input_idx, value);
},
// TODO: MODAMT
// QuickMessage::ModamtUpdate { input_idx, modamt } => {
QuickMessage::ModamtUpdate { .. } => {
// assign to NodeProg
},
QuickMessage::SetMonitor { bufs } => {
self.monitor_signal_cur_inp_indices = bufs;
},