diff --git a/src/dsp/satom.rs b/src/dsp/satom.rs index 9e6e48c..f1ecae7 100644 --- a/src/dsp/satom.rs +++ b/src/dsp/satom.rs @@ -2,7 +2,7 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum SAtom { Str(String), MicroSample(Vec), diff --git a/src/matrix.rs b/src/matrix.rs index fa7164c..8610690 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -652,7 +652,7 @@ impl Matrix { } /// Iterates through all atoms. This is useful for reading - /// the atoms after a [MatrixRepr] has been loaded with [Matrix::from_repr]. + /// all the atoms after a [MatrixRepr] has been loaded with [Matrix::from_repr]. pub fn for_each_atom)>(&self, f: F) { self.config.for_each_param(f); } @@ -664,11 +664,7 @@ impl Matrix { /// should update their knowledge of the nodes in the DSP /// graph. Such as parameter values. /// - /// HexoSynth for instance updates the UI parameters - /// by tracking this value and calling [Matrix::for_each_atom] - /// to retrieve the most current set of parameter values. - /// In case new nodes were created and their default - /// parameter/atom values were added. + /// HexoSynth for instance updates the UI by tracking this value. pub fn get_generation(&self) -> usize { self.gen_counter } /// Returns a serializable representation of the matrix. @@ -790,6 +786,7 @@ impl Matrix { /// assert_eq!(matrix2.get_prop("test").unwrap().i(), 31337); ///``` pub fn set_prop(&mut self, key: &str, val: SAtom) { + self.gen_counter += 1; self.properties.insert(key.to_string(), val); } @@ -848,9 +845,20 @@ impl Matrix { self.config.pop_error() } + /// Retrieve [SAtom] values for input parameters and atoms. + pub fn get_param(&self, param: &ParamId) -> Option { + self.config.get_param(param) + } + /// Assign [SAtom] values to input parameters and atoms. pub fn set_param(&mut self, param: ParamId, at: SAtom) { self.config.set_param(param, at); + self.gen_counter += 1; + } + + /// Retrieve the modulation amount of the input parameter. + pub fn get_param_modamt(&self, param: &ParamId) -> Option { + self.config.get_param_modamt(param) } /// Assign or remove modulation of an input parameter. @@ -858,8 +866,10 @@ impl Matrix { -> Result<(), MatrixError> { if self.config.set_param_modamt(param, modamt) { + // XXX: sync implicitly increases gen_counter! self.sync() } else { + self.gen_counter += 1; Ok(()) } } @@ -1548,4 +1558,40 @@ mod tests { assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)"); assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3|0) in=(4-6|1) at=(0-0) mod=(3-3) cpy=(o1 => i4))"); } + + #[test] + fn check_matrix_set_get() { + use crate::nodes::new_node_engine; + + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let pa1 = NodeId::Sin(1).param_by_idx(0).unwrap(); + let pa2 = NodeId::Sin(1).param_by_idx(1).unwrap(); + let pb1 = NodeId::Sin(2).param_by_idx(0).unwrap(); + let pb2 = NodeId::Sin(2).param_by_idx(1).unwrap(); + let px1 = NodeId::BOsc(1).param_by_idx(0).unwrap(); + let px2 = NodeId::BOsc(1).param_by_idx(1).unwrap(); + + let gen1 = matrix.get_generation(); + matrix.set_param(pa1, (0.75).into()); + matrix.set_param(pa2, (0.50).into()); + matrix.set_param(pb1, (0.25).into()); + matrix.set_param(pb2, (0.20).into()); + matrix.set_param(px1, (0.10).into()); + matrix.set_param(px2, (0.13).into()); + + assert_eq!(matrix.get_generation(), gen1 + 6); + + assert_eq!(matrix.get_param(&pa1), Some((0.75).into())); + + let _ = matrix.set_param_modamt(pa2, Some(0.4)); + let _ = matrix.set_param_modamt(pa1, Some(0.4)); + let _ = matrix.set_param_modamt(pa1, None); + + assert_eq!(matrix.get_generation(), gen1 + 9); + + assert_eq!(matrix.get_param_modamt(&pa2), Some(0.4)); + assert_eq!(matrix.get_param_modamt(&pa1), None); + } } diff --git a/src/nodes/node_conf.rs b/src/nodes/node_conf.rs index d1bb25d..698887d 100644 --- a/src/nodes/node_conf.rs +++ b/src/nodes/node_conf.rs @@ -339,6 +339,13 @@ impl NodeConfigurator { self.nodes.get_mut(idx) } + /// Returns the current modulation amount of the given parameter. + /// Returns `None` if no modulation amount if set and thus no + /// implicit attenuverter is set. + pub fn get_param_modamt(&self, param: &ParamId) -> Option { + self.param_modamt.get(¶m).copied().flatten() + } + /// 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 @@ -386,6 +393,15 @@ impl NodeConfigurator { } } + /// Retrieve [SAtom] values for input parameters and atoms. + pub fn get_param(&self, param: &ParamId) -> Option { + if param.is_atom() { + self.atom_values.get(param).cloned() + } else { + self.param_values.get(param).map(|v| (*v).into()) + } + } + /// Assign [SAtom] values to input parameters and atoms. /// /// Only updates the DSP backend if [NodeConfigurator::rebuild_node_ports] was called